﻿using System.Threading;
using Rhino.Mocks;
using ThreadingPrimeNumberSample;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using ThreadingPrimeNumberSample.Core;

namespace ThreadNumberSampleTests
{
    [TestClass()]
    public class PrimeMVVMViewModelTests
    {
        [TestMethod]
        public void StartStop_ContinueIsTrue_ContinueSetToFalse()
        {
            // Arrange
            var primeEngineMock
                = MockRepository.GenerateMock<IPrimeEngine>();
            var threadProxyStub
                = MockRepository.GenerateStub<IThreadProxy>();
            var target = new PrimeMVVMViewModelHarness(primeEngineMock, threadProxyStub);
            primeEngineMock.Stub(p => p.Continue).Return(true);
            primeEngineMock.Expect(p => p.Continue).
                SetPropertyWithArgument(false);

            // Act
            target.CallStartStop();

            // Assert
            primeEngineMock.VerifyAllExpectations();
        }

        [TestMethod]
        public void StartStop_ContinueIsTrue_ButtonTextSetToResume()
        {
            // Arrange
            var primeEngineStub
                = MockRepository.GenerateStub<IPrimeEngine>();
            var threadProxyStub
                = MockRepository.GenerateStub<IThreadProxy>();
            var target = new PrimeMVVMViewModelHarness(primeEngineStub, threadProxyStub);
            primeEngineStub.Continue = true;

            // Act
            target.CallStartStop();

            // Assert
            Assert.AreEqual(Strings.Stop, target.ButtonText);
        }

        [TestMethod]
        public void StartStop_ContinueIsFalse_ButtonTextSetToStop()
        {
            // Arrange
            var primeEngineStub
                = MockRepository.GenerateStub<IPrimeEngine>();
            var threadProxyStub
                = MockRepository.GenerateStub<IThreadProxy>();
            var target = new PrimeMVVMViewModelHarness(primeEngineStub, threadProxyStub);
            primeEngineStub.Continue = false;

            // Act
            target.CallStartStop();

            // Assert
            Assert.AreEqual(Strings.Resume, target.ButtonText);
        }

        [TestMethod]
        public void StartStop_Always_WorkerThreadIDSetFromThreadProxy()
        {
            // Arrange
            const int expectedThreadID = 9;
            var primeEngineStub
                = MockRepository.GenerateStub<IPrimeEngine>();
            var threadProxyStub
                = MockRepository.GenerateStub<IThreadProxy>();
            var target = new PrimeMVVMViewModelHarness(primeEngineStub, threadProxyStub);
            threadProxyStub.Stub(t => t.GetCurrentThreadID()).
                Return(expectedThreadID);

            // Act
            target.CallCheckNextNumber(null);

            // Assert
            Assert.AreEqual(expectedThreadID, target.WorkerThreadID);
        }

        [TestMethod]
        public void StartStop_Always_GetNextPrimeValueCalled()
        {
            // Arrange
            var primeEngineMock
                = MockRepository.GenerateMock<IPrimeEngine>();
            var threadProxyStub
                = MockRepository.GenerateStub<IThreadProxy>();
            var target = new PrimeMVVMViewModelHarness(primeEngineMock, threadProxyStub);

            // Act
            target.CallCheckNextNumber(null);

            // Assert
            primeEngineMock.AssertWasCalled(p => p.GetNextPrimeValue());
        }

        [TestMethod]
        public void _primeEngine_PrimeFound_Always_SetsPrimeNumber()
        {
            // Arrange
            const int expectedPrime = 9;
            var primeEngineMock
                = MockRepository.GenerateStub<IPrimeEngine>();
            var threadProxyStub
                = MockRepository.GenerateStub<IThreadProxy>();
            var target = new PrimeMVVMViewModelHarness(primeEngineMock, threadProxyStub);
            var primeFoundEventArgs = new PrimeFoundEventArgs
                                          {Prime = expectedPrime};

            // Act
            target.Call_primeEngine_PrimeFound(null, primeFoundEventArgs);

            // Assert
            Assert.AreEqual(expectedPrime, target.PrimeNumber);
        }

        private class PrimeMVVMViewModelHarness : PrimeMVVMViewModel
        {
            public PrimeMVVMViewModelHarness(IPrimeEngine primeEngine, 
                IThreadProxy threadProxy) 
                : base(primeEngine, threadProxy)
            {
            }

            public void CallStartStop()
            {
                StartStop();
            }

            public void CallCheckNextNumber(object state)
            {
                CheckNextNumber(state);
            }

            public void Call_primeEngine_PrimeFound(object sender,
                PrimeFoundEventArgs e)
            {
                _primeEngine_PrimeFound(sender, e);
            }
        }
    }
}
